import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit

x_lim_all = (-6, 6)
y_lim_all = (-5, 35)#这两个千万不要放到test6()这个函数里面 否则就失效了
def test6():
    """已经实现了从鼠标点 然后正弦曲线下移的动态操作"""
    # 先生成一群点，把点画出来
    fig, ax = plt.subplots()
    x = np.array([-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]).astype(np.float64)  # 点的横坐标，放在一个数组里面
    y = np.square(x).astype(np.float64)  # y=x^2,根据x生成y的坐标，我这里用的二次曲线方程
    plt.xlim(-6, 6)  # 坐标系x轴范围
    plt.ylim(-5, 35)  # 坐标系y轴范围
    ax.scatter(x, y)  # 画成散点图
    # 忽略除以0的报错
    np.seterr(divide='ignore', invalid='ignore')
    print("点击鼠标左键    当前的x_lim_all:\t",x_lim_all,"\t\t当前的y_lim_all:\t",y_lim_all)
    # 二阶曲线方程
    def func_2(x, a, b, c):
        return a * np.power(x, 2) + b * x + c

    # 鼠标点击事件  函数里面又绑定了一个鼠标移动事件，所以生成的效果是鼠标按下并且移动的时候
    def on_button_press(event):
        if event.button==1:
            # global x_lim_all
            # global y_lim_all
            print("点击鼠标左键    当前的x_lim_all:\t",x_lim_all,"\t\t当前的y_lim_all:\t",y_lim_all)
        fig.canvas.mpl_connect('motion_notify_event', on_button_move)

    # on_button_move 鼠标移动事件
    def on_button_move(event, y=y):
        current_ax = event.inaxes
        if event.button == 2:  # 1、2、3分别代表鼠标的左键、中键、右键，我这里用的是鼠标中键，根据自己的喜好选择吧
            x_mouse, y_mouse = event.xdata, event.ydata  # 拿到鼠标当前的横纵坐标
            ind = []  # 这里生成一个列表存储一下要移动的那个点
            # 计算一下鼠标的位置和图上点的位置距离，如果距离很近就移动图上那个点
            for i in range(len(x)):
                # 计算一下距离 图上每个点都和鼠标计算一下距离
                d = np.sqrt((x_mouse - x[i]) ** 2 + (y_mouse - y[i]) ** 2)
                if d < 0.8:  # 这里设置一个阈值，如果距离很近，就把它添加到那个列表中去
                    ind.append(i)

            if ind:  # 如果ind里面有元素，说明当前鼠标的位置距离图上的一个点很近
                # 通过索引ind[0]去改变当前这个点的坐标，新坐标是当前鼠标的横纵坐标（这样给人的感觉就是这个点跟着鼠标动了）
                y[ind[0]] = y_mouse
                x[ind[0]] = x_mouse

                # 然后根据所有点拟合出来一个二次方程曲线
                popt2, pcov2 = curve_fit(func_2, x, y)
                a2 = popt2[0]
                b2 = popt2[1]
                c2 = popt2[2]
                yvals2 = func_2(x, a2, b2, c2)

                # 拟合好了以后把曲线画出来
                ax.cla()
                print("中键   当前的x_lim_all:\t", x_lim_all, "\t\t当前的y_lim_all:\t", y_lim_all)
                current_ax.set(xlim=x_lim_all,
                               ylim=y_lim_all)
                ax.scatter(x, y)
                # current_ax.set(xlim=x_lim_all,
                #                ylim=y_lim_all)
                ax.plot(x, yvals2)
                fig.canvas.draw_idle()  # 重新绘制整个图表，所以看到的就是鼠标移动点然后曲线也跟着在变动

    def on_button_release(event):
        fig.canvas.mpl_disconnect(fig.canvas.mpl_connect('motion_notify_event', on_button_move))  # 鼠标释放事件

    def enlarge(event):
        global x_lim_all
        global y_lim_all
        x, y = event.xdata, event.ydata #这个暂时没有用上
        current_ax=event.inaxes
        xmin, xmax = current_ax.get_xlim()
        ymin, ymax = current_ax.get_ylim()
        x_step1,x_step2=(x-xmin)/10,(xmax-x)/10
        y_step1,y_step2=(y-ymin)/10,(ymax-y)/10

        if event.button=="up":#
            #鼠标向上滚动，缩小坐标轴刻度范围，使得图形变大
            x_lim_all=(xmin+x_step1,xmax-x_step2)
            y_lim_all=(ymin + y_step1, ymax - y_step2)
            current_ax.set(xlim=x_lim_all,
                           ylim=y_lim_all)
        if event.button=="down":#
            #鼠标向下滚动，增加坐标轴刻度范围，使得图形变小
            x_lim_all=(xmin-x_step1,xmax+x_step2)
            y_lim_all=(ymin-y_step1, ymax+y_step2)
            current_ax.set(xlim=x_lim_all,
                           ylim=y_lim_all)

        fig.canvas.draw_idle()

    print("最下面的x_lim_all:\t",x_lim_all,"\t\t当前的y_lim_all:\t",y_lim_all)
    fig.canvas.mpl_disconnect(fig.canvas.manager.key_press_handler_id)  # 取消默认快捷键的注册
    fig.canvas.mpl_connect('button_press_event', on_button_press)#鼠标点击事件
    fig.canvas.mpl_connect('button_release_event', on_button_release)#鼠标松开
    fig.canvas.mpl_connect('scroll_event', enlarge)#鼠标滚轮滚动事件
    plt.show()

if __name__ == '__main__':
    test6()